package com.atguigu.tingshu.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.account.UserAccount;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.user.config.PrivateKeyConfigInt;
import com.atguigu.tingshu.user.config.wxConfig;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.atguigu.tingshu.common.result.ResultCodeEnum.*;


@Slf4j
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private UserInfoMapper userInfoMapper;


	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private wxConfig wxConfig;

	@Autowired
	private PrivateKeyConfigInt privateKeyConfigInt;

	@Autowired
	private RabbitTemplate rabbitTemplate;

	/**
	 * 登录发放token
	 *
	 * @param code
	 * @return
	 */
	@Override
	public Map wxLogin(String code) {
		//验证code是否为空
		//初始化url
		String url = "https://api.weixin.qq.com/sns/jscode2session?";
		//获取四个参数
		// appid=APPID
		url += "appid="+wxConfig.getAppId();
		// &secret=SECRET
		url += "&secret=" + wxConfig.getAppSecret();
		// &js_code=JSCODE
		url += "&js_code="+code;
		// &grant_type=authorization_code
		url += "&grant_type=authorization_code" ;
		//使用resTemplate向微信服务器发起请求
		ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
		//获取请求体
		String result = exchange.getBody();
		//反序列化，将对象转换为JSON类型的字符串
		JSONObject jsonObjectresult = JSON.parseObject(result,JSONObject.class);
		//获取openid
		String openid = jsonObjectresult.getString("openid");
		//
		String password = "1321465";
		BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
		String encoded = bCryptPasswordEncoder.encode(password);
		//根据openid查询数据库是否为空
		UserInfo userInfo = getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getWxOpenId, openid));
		//判断用户是否注册
		if(userInfo==null){
			//初始化用户信息
			userInfo = new UserInfo();
			userInfo.setWxOpenId(openid);
			userInfo.setNickname("新用户");
			userInfo.setAvatarUrl("http://www.atguigu.com/images/index_new/logo.png");//头像图片链接
			userInfo.setPassword(encoded);
			save(userInfo);
			//通知账号模块初始化账户信息 -》 rabbitmq
			//先实名认证后开通账户功能
			rabbitTemplate.convertAndSend("User_Account_Exchange","init_Account",userInfo.getId()+"");
		}
		else {
			userInfo.setPassword(encoded);
			updateById(userInfo);
		}

		//生成token
		Map map = new HashMap();
		map.put("userId",userInfo.getId());//载荷包含用户信息
		map.put("Time", System.currentTimeMillis()+ 60000);//载荷，设置token过期时间10分钟
		map.put("vipExpireTime", userInfo.getVipExpireTime() ==null
				? null
				: userInfo.getVipExpireTime().getTime());

		Jwt encode = JwtHelper.encode(JSONObject.toJSONString(map), new RsaSigner(privateKeyConfigInt.privateKey()));//签名部分
		String token = encode.getEncoded();

		map = new HashMap();
		map.put("token",token);
		return map;
	}

	/**
	 * 刷新令牌
	 * @param mNum
	 * @return
	 */
	@Override
	public Result getNewToken(String mNum) {
		Map map = new HashMap();
		//获取旧的token
		ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
		String token = requestAttributes.getRequest().getHeader("token");
		try {
			if (token.isEmpty()){
				throw new GuiguException(LOGIN_AUTH);
			}
			//解密token
			Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(privateKeyConfigInt.publicKey()));
			//获取载荷
			String claims = jwt.getClaims();
			//反序列化
			JSONObject jsonObject = JSONObject.parseObject(claims);
			//对旧的token进行校验
			//解析载荷头部签名，是否匹配
			//对比上一次登录的设备号
			Long userId = jsonObject.getLong("userId");
			//获取user对象，用于获取存在数据库的设备号
			UserInfo userinfo = getById(userId);
			Date vipExpireTime = userinfo.getVipExpireTime();
			BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
			//判断是不是同一个设备,暂时以密码作为设备号
			if (bCryptPasswordEncoder.matches(mNum,userinfo.getPassword())){
				//是：生成新的token
				map.put("UserId",userId);//头部包含用户信息
				map.put("vipExpireTime",vipExpireTime.getTime());
				//载荷，设置token过期时间10分钟
				map.put("Time", System.currentTimeMillis()+ 600000);
				Jwt encode = JwtHelper.encode(JSONObject.toJSONString(map), new RsaSigner(privateKeyConfigInt.privateKey()));//签名部分
				token = encode.getEncoded();
				map.put("token",token);

			}//不是同一台设备，抛出异常，重新登录
			else {
				throw new GuiguException(LOGIN_AUTH);
			}
			//token校验失败
		}catch ( Exception e){
			throw  new GuiguException(SIGN_ERROR);
		}
			return Result.ok(map);
		}

	/**
	 * 获取用户信息
	 */
	@Override
	public UserInfo getUserInfo() {
		return getById(AuthContextHolder.getUserId());
	}

}
